#include "wingbot_usart.h"
#include "wingbot_queue.h"

uint8_t usart1_rx_buffer[512];
Queue_T usart1_rx_queue;

uint8_t usart2_rx_buffer[128];
Queue_T usart2_rx_queue;

uint8_t usart3_rx_buffer[128];
Queue_T usart3_rx_queue;

uint8_t usart4_rx_buffer[128];
Queue_T usart4_rx_queue;

uint8_t usart5_rx_buffer[128];
Queue_T usart5_rx_queue;

#define wing_tx_waiting(t) if(t--==0){ \
                             ret = TRANS_TIMEOUT;\
                             break;}

#define wing_usart_queue_init(n) do {\
    queue_init(&usart##n##_rx_queue, (uint8_t *)usart##n##_rx_buffer, sizeof(usart##n##_rx_buffer)); \
    }while(0);

/**
* @brief  串口初始化，初始化接收队列和接收缓存，
          命名规则必须符合usart?_rx_queue, usart?_rx_buffer，?表示通道编号，
          默认使能串口但不开中断，该函数不配置GPIO
* @param  USARTx: Channel of USART port 1~6
*         baudrate: 波特率
          parity: 奇偶校验位
          stopbits: 停止位
  */
void wing_usart_init(USART_TypeDef *USARTx,
                      uint32_t baudrate,
                      uint16_t parity,
                      uint16_t stopbits)
{
    USART_InitTypeDef USART_InitStructure;
    /* Configure USART Port */
    USART_InitStructure.USART_BaudRate = baudrate;
    if (parity != USART_Parity_No)
        USART_InitStructure.USART_WordLength = USART_WordLength_9b; //如果选择偶校验就要把校验位也加上，因此是9位
    else
        USART_InitStructure.USART_WordLength = USART_WordLength_8b;
    USART_InitStructure.USART_StopBits = stopbits;
    USART_InitStructure.USART_Parity = parity;
    USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
    USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;

    if (USARTx == USART1)
    {
        RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1, ENABLE);
        wing_usart_queue_init(1);
    }
    else if (USARTx == USART2)
    {
        RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART2, ENABLE);
        wing_usart_queue_init(2);
    }
    else if (USARTx == USART3)
    {
        RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART3, ENABLE);
        wing_usart_queue_init(3);
    }
    else if (USARTx == UART4)
    {
        RCC_APB1PeriphClockCmd(RCC_APB1Periph_UART4, ENABLE);
        wing_usart_queue_init(4);
    }
    else if (USARTx == UART5)
    {
        RCC_APB1PeriphClockCmd(RCC_APB1Periph_UART5, ENABLE);
        wing_usart_queue_init(5);
    }

    /* Start USART */
    USART_Init(USARTx, &USART_InitStructure);
    USART_Cmd(USARTx, ENABLE);
}

/**
* @brief: 中断初始化
*/
void wing_usart_nvic_init(USART_TypeDef *USARTx)
{
    NVIC_InitTypeDef NVIC_InitStructure = {0};
    
    if(USARTx == USART1)
        NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn;
    else if(USARTx == USART2)
        NVIC_InitStructure.NVIC_IRQChannel = USART2_IRQn;
    else if(USARTx == USART3)
        NVIC_InitStructure.NVIC_IRQChannel = USART3_IRQn;
    else if(USARTx == UART4)
        NVIC_InitStructure.NVIC_IRQChannel = UART4_IRQn;
    else if(USARTx == UART5)
        NVIC_InitStructure.NVIC_IRQChannel = UART5_IRQn;
    
    NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;
    NVIC_InitStructure.NVIC_IRQChannelSubPriority = 3;
    NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
    NVIC_Init(&NVIC_InitStructure);
    USART_ClearFlag(USARTx, USART_FLAG_TC);
    USART_ITConfig(USARTx, USART_IT_RXNE, ENABLE);
}

void wing_usart_send_string(USART_TypeDef* USARTx, const char* msg)
{
    uint16_t i = 0;
    uint8_t *pstr = (uint8_t*)msg;
    for(i=0;i<UART_MAX_STRING;i++)
    {
        if(*msg == 0)
            break;
        msg++;
    }
    if(i != UART_MAX_STRING)
    {
        wing_usart_send_bytes(USARTx, pstr, i);
    }
}

void wing_usart_send_bytes(USART_TypeDef* USARTx, uint8_t* p, uint16_t len)
{
    uint16_t i;
    for(i=0;i<len;i++)
        wing_usart_send_byte(USARTx, *p++);
}

void wing_clear_buffer(u8* p, u16 len)
{
    u16 i = 0;
    for(i=0;i<len;i++)
        *p++ = 0;
}

/**
* @brief  Send One Byte through USARTx port
* @param  USARTx: Channel of USART port 1~6
                        data: 发送的内容
* @retval TRANS_OK: 发送成功
  */
TRANS_STATUS wing_usart_send_byte(USART_TypeDef *USARTx, unsigned char data)
{
    TRANS_STATUS ret = TRANS_OK;
    uint32_t time = USART_TX_TIMEOUT;
    while (USART_GetFlagStatus(USARTx, USART_FLAG_TC) == RESET){wing_tx_waiting(time);}
    USART_SendData(USARTx, data);
    time = USART_TX_TIMEOUT;
    while (USART_GetFlagStatus(USARTx, USART_FLAG_TC) == RESET){wing_tx_waiting(time);}
    return ret;
}
